﻿using System;
using System.Collections.Generic;
using DC2010.Objects.Base;
using System.Xml.Serialization;
using DC2010.Objects.Common;
using DC2010.Objects.Structures;

namespace DC2010.Objects.Data
{
	// ItemLogic - IToogle means switch item to alter state
	// 
    [Serializable]
    public class ItemInfo : BaseInfo
    {
        public ItemInfo()
        {
            Weight = 0;

            ContainerItems = new Inventory();
            SocketedItems = new Inventory();

            //events
            OnUseEffects = new List<KeyValue>();
            Combo = new List<string>();
        }

        /// <summary>
		/// TODO: Any item can be improved with other items.
		/// </summary>
        public Inventory SocketedItems { get; set; }

        /// <summary>
        /// Reference to ActionInfo. We will need data of this as well. Create System for this. 
		/// ActionInfo should reference I_Effect - Instant effects.
		/// Logic should look like this:
		/// 1. Do some action
		/// 2. ActionData will reference Effects which will defined earlier.
		/// 3. Most of such effects will reference Calculations.cs
		///
		/// In extreme situations we can create double swing action simply by adding two swing effects to action.
        /// </summary>
        public List<string> Combo { get; set; }

		/// <summary>
        /// If I will have this item in hand and i will click on another item those effects are called
        /// instant parts, first parameter will be this item, second parameter will be clicked item.
        ///
        /// so if i take a key into hand and click with this key on keylock effect will be triggered.
        /// Instant(this, clicked item)
        ///
        /// If ill have an effect I_UNLOCK then ill get
        /// I_UNLOCK_EFFECT("Emerald key", "Emerald keyhole")
        ///
        /// "Emerald keyhole" is real object. every object have property "linked objects"
        /// that linked object should be implemented IToogle interface.
        /// IToogle.Toogle(BaseItem caller, BaseItem toogler);
        /// IToogle.Toogle("Emerald keyhole", "Emerald Key");
		///
		/// Other possible effect will be for portait on the wall.
		/// This item will be marked as "WallItem" with specific effect.
		/// I_PICKCHAMPION(null(i clicked with hand or here will be item in hand), this)
		/// this should contain info about champion. For example in params.
		/// Such a wallitem should be marked and portrait_XY.
		/// </summary>
        public List<KeyValue> OnUseEffects { get; set; }

		/// <summary>
		/// Weight of the object. If this item is container use L.GetWeight method.
		/// </summary>
        public double Weight { get; set; }
		
		/// <summary>
		/// Some item can be placed only to certain positions. 
		/// Here are positions which are not allowed. 
		/// For example helms will not be possible to put on legs.
		/// </summary>		
        public List<CarryLocations> ForbiddenEquipSlots { get; set; }

		/// <summary>
		/// Some monsters can be hit only certain items. 
		/// </summary>		
		[Obsolete("DO NOT USE: This is replaced with Effect from Action. Effect will decide whether hit or not hit immaterial being. Action: ACTION_DISRUPT call effect I_ACTION_DISRUPT_EFFECT.")]
        public bool HitImmaterial { get; set; }
        
		/// <summary>
		/// Power of curse (0 for not cursed). 
		/// Remove curse decreases this, item can't be removed until cursed==0 (not implemented yet)
		/// If item is cursed and equipped - it cannot be unequipped.
		/// </summary>		
		public int IsCursed { get; set; }                           
		
        
// Container part
		
		/// <summary>
		/// Defines if this object can contain other objects.
		/// Chest, Boxes, Alcove, etc ...
		/// </summary>		
        public bool IsContainerItem { get; set; }
		
		/// <summary>
		/// For example alcove has this set to true, it means that container items will be displayed. 
		/// On false no alcove will be displayed. It must be first switched to true. Alcove can be hidden
		/// beneath another wall item. For example button or painting.
		///
		/// We can use this for Chest in inventory as well. Question is how can we lock up chest?
		/// Answer: Item will implement toogle interface.
		/// Answer2: Use one item ower another item. Items can be combined.
		/// Answer3: If target item is wall item - it can do something else :)
		/// </summary>		
        public bool IsContainerItemsDisplayed { get; set; }
		
		/// <summary>
		/// What type of items this container accepts. For example moneybox accept only Money. ContainerType |= ItemType.Sword | ItemType.Axe
		/// </summary>	
        public ItemType ContainerType { get; set; }                 
		
		/// <summary>
		/// List of items in container
		/// </summary>	
        public Inventory ContainerItems { get; set; }       
		
		/// <summary>
		/// Item required for opening a container. If empty then container is opened. IToogle interface checks for this.
		/// </summary>	
        public string ContainerKey { get; set; }            

		/// <summary>
		/// Pressure pad, etc. Item cannot be picked up. If it is container item items can be retrieved and container locked. For example grate and key in grate.
		/// </summary>			
        public bool IsFloorItem { get; set; }
		
		/// <summary>
		/// Mirror, keyholes, alcoves, ...
        /// </summary>
		public bool IsWallItem { get; set; }

        /// <summary>
        /// This indicates that scroll in inventory will be displayed
        /// </summary>
        public string ItemMessage { get; set; }

        public ItemType ItemType { get; set; }

        /// <summary>
        /// Is can that item is bow, crosbow - ammo is required.
        /// </summary>
        public AmmoType AmmoType { get; set; }

        /// <summary>
        /// The base number used to calculate how much damage your attack does.
        /// </summary>
        public int Damage { get; set; }

        /// <summary>
        /// This value determines how far the item will go when thrown.
        /// If a weapon is used to "Shoot", this will be a part of how far the item being shot will travel. 
        /// The farther the projectile goes, the more damage it does (Damage is decreased as it flies).
        /// </summary>
        public int Distance { get; set; }

        /// <summary>
        /// The amount of damage associated with fired projectiles.
        /// </summary>
        public int ShootDamage { get; set; }

        /// <summary>
        /// The weapon class and delta energy (only for bows and slings) lost for each dungeon tile the missile travels.
        /// </summary>
        public int DeltaEnergy { get; set; }

//        /// <summary>
//        /// A 0..7 value which is used when monsters have a "sharp" attack. 
//        /// Sharp attacks use the following format to calculate armor: 
//        /// (Sharp Resistance / 7) * Armor Strength, so if the Sharp Resistance value is 0, 
//        /// a creature having a Sharp attack will ignore your armor.
//        /// </summary>
//        public int SharpResistance { get; set; }
		
		/// <summary>
		/// Important for armor. Contains Fire, Poison, Sharp, Blunt.
		/// </summary>
		public Resistances Resistances {get; set; }

        /// <summary>
        /// The armor value (0..200) associated with the item.
        /// </summary>
        public int ArmorStrength { get; set; }

        public ItemData CreateData()
        {
            ItemData id = new ItemData();

            id.InfoId = Id;
            id.Id = id.InfoId+"_"+Guid.NewGuid().ToString();
            id.GfxId = GfxId;
            id.Type = Type;
			
			id.SocketedItems = (Inventory)SocketedItems.Clone();
			id.Combo = new List<string>();
            id.ItemMessage = ItemMessage;
			
			// Instantiate Actions
            foreach (string action in Combo)
            {
                ActionInfo ii = Root.I.ActionSystem.GetInfo(action);
				id.Combo.Add(ii.CreateData().Id);
            }	

			// Doplnit veci z: http://dmweb.free.fr/?q=node/259

			
            //TODO: fill with other properties
            Root.log.InfoFormat("Core, Created new object with id: {0} based on object {1}", id.Id, id.InfoId);

            Root.I.ItemSystem.AddData(id);

            return id;
        }
    }
}
